package cn.com.sinux.spring.utils;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: New
 * Date: 13-2-3
 * Time: 下午5:07
 * To change this template use File | Settings | File Templates.
 */
public class DateUtils extends org.apache.commons.lang.time.DateUtils {

    public static final String YMD = "yyyyMMdd";
    public static final String YMD_SLASH = "yyyy/MM/dd";
    public static final String YMD_DASH = "yyyy-MM-dd";
    public static final String YMD_DASH_WITH_TIME = "yyyy-MM-dd H:m";
    public static final String YDM_SLASH = "yyyy/dd/MM";
    public static final String YDM_DASH = "yyyy-dd-MM";
    public static final String HM = "HHmm";
    public static final String HM_COLON = "HH:mm";
    public static final long DAY = 24 * 60 * 60 * 1000L;

    public static final String TYPE_MONTH = "MONTH";
    public static final String TYPE_WEEK = "WEEK";


    /**
     * Short pattern of date.
     */
    public static final String shortPattern = "yyyy-MM-dd";

    public static final String TIME_PATTERN = "yyyy-MM-dd HH:mm";
    /**
     * Default date formate pattern.
     */
    public static final String defaultPattern = "yyyy-MM-dd HH:mm:ss";

    public static final String defaultPatternWithZone = "yyyy-MM-dd HH:mm:ss z";


    private static final Map<String, DateFormat> DFS = new HashMap<String, DateFormat>();

    private DateUtils() {
    }

    private static DateFormat getFormat(String pattern) {
        DateFormat format = DFS.get(pattern);
        if (format == null) {
            format = new SimpleDateFormat(pattern);
            DFS.put(pattern, format);
        }
        return format;
    }

    public static Date getEndOfDay(Date day) {
        return getEndOfDay(day, Calendar.getInstance());
    }

    public static Date getEndOfDay(Date day, Calendar cal) {
        if (day == null) day = new Date();
        cal.setTime(day);
        cal.set(Calendar.HOUR_OF_DAY, cal.getMaximum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getMaximum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getMaximum(Calendar.SECOND));
        cal.set(Calendar.MILLISECOND, cal.getMaximum(Calendar.MILLISECOND));
        return cal.getTime();
    }

    public static Date getStartOfDay(Date day) {
        return getStartOfDay(day, Calendar.getInstance());
    }

    public static Date getStartOfDay(Date day, Calendar cal) {
        if (day == null) day = new Date();
        cal.setTime(day);
        cal.set(Calendar.HOUR_OF_DAY, cal.getMinimum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND));
        cal.set(Calendar.MILLISECOND, cal.getMinimum(Calendar.MILLISECOND));
        return cal.getTime();
    }

    /**
     * 两个日期之间相隔天数的共通.
     *
     * @param nowDate
     * @param endDate
     * @return
     */
    public static long getDaysBetweenTwoDates(Date nowDate, Date endDate) throws ParseException {
        return getDaysBetweenTwoDates(formatDate(nowDate), formatDate(endDate));
    }

    public static Date[] getYearRange(int year) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, 0);
        cal.set(Calendar.DATE, cal.getMinimum(Calendar.DATE));
        cal.set(Calendar.HOUR_OF_DAY, cal.getMinimum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND));
        cal.set(Calendar.MILLISECOND, cal.getMinimum(Calendar.MILLISECOND));
        Date time = cal.getTime();
        cal.set(Calendar.MILLISECOND, cal.getMinimum(Calendar.MILLISECOND));
        return new Date[]{time, DateUtils.addMilliseconds(DateUtils.addYears(time, 1), -1)};
    }

    /**
     * @param year 获取某年
     * @param type 类型
     * @return
     */
    public static List<Date[]> getDatesOfYear(int year, String type) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, 0);
        cal.set(Calendar.HOUR_OF_DAY, cal.getMinimum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND));
        List<Date[]> dates = new LinkedList<Date[]>();
        if (TYPE_MONTH.equals(type)) {
            for (int i = 0; i < 12; i++) {
                cal.set(Calendar.DAY_OF_MONTH, cal.getMinimum(Calendar.DAY_OF_MONTH));
                Date begin = cal.getTime();
                cal.set(Calendar.MONTH, i + 1);
                dates.add(new Date[]{begin, new Date(cal.getTimeInMillis() - 1)});
            }
        } else if (TYPE_WEEK.equals(type)) {
            cal.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
            cal.set(Calendar.WEEK_OF_YEAR, 1);
//            for (int i = 1, l = cal.getWeeksInWeekYear(); i <= l; i++) {
//                Date begin = cal.getTime();
//                cal.set(Calendar.WEEK_OF_YEAR, i + 1);
//                dates.add(new Date[]{begin, new Date(cal.getTimeInMillis() - 1)});
//            }
        }
        return dates;
    }

    /**
     * 两个日期之间相隔天数的共通.
     *
     * @param nowDate 開始時間
     * @param endDate 　終了時間
     * @return　 天数
     */
    public static long getDaysBetweenTwoDates(String nowDate, String endDate) throws ParseException {
        Date dtFrom;
        Date dtEnd;
        String[] pattens = new String[]{shortPattern};
        dtFrom = parseDate(nowDate, pattens);
        dtEnd = parseDate(endDate, pattens);
        long begin = dtFrom.getTime();
        long end = dtEnd.getTime();
        long inter = end - begin;
        if (inter < 0) {
            inter = inter * (-1);
        }
        long dateMillSec = 24 * 60 * 60 * 1000;

        long dateCnt = inter / dateMillSec;

        long remainder = inter % dateMillSec;

        if (remainder != 0) {
            dateCnt++;
        }
        return dateCnt;
    }

    /**
     * Format date with given pattern.
     *
     * @param date    Date to be formated.
     * @param pattern Pattern.
     * @return Date in proper format.
     */
    public static String formatDate(Date date, String pattern) {
        if (StringUtils.isBlank(pattern)) {
            pattern = defaultPattern;
        }

        if (date == null) {
            return StringUtils.EMPTY;
        }

        return new SimpleDateFormat(pattern).format(date);
    }

    public static String formatDate(Date date, String pattern, String timeZone) {
        if (StringUtils.isBlank(pattern)) {
            pattern = defaultPatternWithZone;
        }

        if (StringUtils.isBlank(timeZone)) {
            timeZone = "GMT";
        }

        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        sdf.setTimeZone(TimeZone.getTimeZone(timeZone));

        return sdf.format(date);
    }

    public static boolean between(Date date, Date[] range) {
        return date.compareTo(range[0]) >= 0 && date.compareTo(range[1]) <= 0;
    }

    /**
     * Format date with given pattern.
     *
     * @param date Date to be formated.
     * @return Date in proper format.
     */
    public static String formatDate(Date date) {
        return formatDate(date, defaultPattern);
    }

    /**
     * 针对指定日志，累加指定天数
     *
     * @param date
     * @param amount
     * @return
     */
    public static Date dateAdd(Date date, int amount) {
        Date addDate = null;
        if (date != null) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.add(Calendar.DAY_OF_MONTH, amount);
            addDate = new Date(cal.getTime().getTime());
        }
        return addDate;

    }

    public static Date getStartDayOfWeek(Date time){
        Calendar cal = Calendar.getInstance();
        if(time != null){
            cal.setTime(time);
        }
        cal.set(Calendar.DAY_OF_WEEK, cal.getMinimum(Calendar.DAY_OF_WEEK));
        cal.set(Calendar.HOUR_OF_DAY, cal.getMinimum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND));
        return cal.getTime();
    }

    public static Date getStartDayOfMonth(Date time){
        Calendar cal = Calendar.getInstance();
        if(time != null){
            cal.setTime(time);
        }
        cal.set(Calendar.DAY_OF_MONTH, cal.getMinimum(Calendar.DAY_OF_MONTH));
        cal.set(Calendar.HOUR_OF_DAY, cal.getMinimum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND));
        return cal.getTime();
    }


    public static Date getStartDayOfYear(Date time){
        Calendar cal = Calendar.getInstance();
        if(time != null){
            cal.setTime(time);
        }
        cal.set(Calendar.DAY_OF_YEAR, cal.getMinimum(Calendar.DAY_OF_YEAR));
        cal.set(Calendar.HOUR_OF_DAY, cal.getMinimum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND));
        return cal.getTime();
    }

    public static Date getEndDayOfYear(Date time){
        Calendar cal = Calendar.getInstance();
        if(time != null){
            cal.setTime(time);
        }
        cal.set(Calendar.DAY_OF_YEAR, cal.getMaximum(Calendar.DAY_OF_YEAR));
        cal.set(Calendar.HOUR_OF_DAY, cal.getMinimum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND));
        return cal.getTime();
    }

    public static Date getEndDayOfMonth(Date time){
        Calendar cal = Calendar.getInstance();
        if(time != null){
            cal.setTime(time);
        }
        Date _time = getStartDayOfMonth(cal.getTime());
        _time = addMonths(_time, 1);
        return addMilliseconds(_time, -1);
    }

    public static void main(String[] args) {
        Date now = new Date();
        int weekEnds = 1;
        Date begin = getStartDayOfWeek(now), end = getStartDayOfWeek(now);
        while (begin.after(end)) {
            begin = DateUtils.addWeeks(begin, -1);
            weekEnds++;
        }
        System.out.print(weekEnds);
    }

    public static List<String> getDateRange(Date startDate, Date endDate) {
        List<String> list = new ArrayList<String>();
        Date flag = DateUtils.getStartOfDay(startDate);
        Date _end = DateUtils.getStartOfDay(endDate);
        while (flag.compareTo(_end) <= 0){
            list.add(DateFormatUtils.format(flag, "yyyy-MM-dd"));
            flag = DateUtils.addDays(flag, 1);
        }
        return list;
    }


    public static List<String> getMonthRange(Date startDate, Date endDate) {
        List<String> list = new ArrayList<String>();
        Date flag = DateUtils.getStartOfDay(startDate);
        Date _end = DateUtils.getStartOfDay(endDate);
        while (flag.compareTo(_end) <= 0){
            list.add(DateFormatUtils.format(flag, "yyyy-MM"));
            flag = DateUtils.addMonths(flag, 1);
        }
        return list;
    }

    public static List<String> getYearRange(Date startDate, Date endDate) {
        List<String> list = new ArrayList<String>();
        Date flag = DateUtils.getStartOfDay(startDate);
        Date _end = DateUtils.getStartOfDay(endDate);
        while (flag.compareTo(_end) <= 0){
            list.add(DateFormatUtils.format(flag, "yyyy"));
            flag = DateUtils.addYears(flag, 1);
        }
        return list;
    }
}
